#include "tim5.h"
#include "sys.h"

/* 以下是一个定时器,到时间将tim2_count + 1 */
volatile uint64_t tim5_count = 0; // 64位存储时间
uint64_t tim5_timer[MAX_TIMER_ID] = {0};

void TIM5_IRQHandler()
{
    // 为什么中断函数返回太快，会被重新置位，没想明白，加一条延时
    TIM5->SR &= (uint16_t)~TIM_IT_Update;
    TIM5->SR &= (uint16_t)~TIM_IT_Update;
    // 整数个6.5536秒存储在16-47位共32位，可以计时上百万年
    (*(uint32_t *)((uint16_t *)(&tim5_count) + 1))++;
}

// 100us计数器增一次， 65536/10000=6.5536s, 进中断一次，可以通过内部变量获得us数，只不过us数是整百的，不能精确到100us以下
void tim5_init(void)
{
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE); // 时钟使能

    // 定时器TIM5初始化
    TIM_DeInit(TIM5);
    TIM_TimeBaseStructure.TIM_Prescaler = clocks.PCLK1_Frequency / 1000000 * 2 * 100 - 1; // 设置用来作为TIMx时钟频率除数的预分频值, CLK1为两分频而来
    TIM_TimeBaseStructure.TIM_Period = 0xFFFF;                                            // 设置在下一个更新事件装入活动的自动重装载寄存器周期的值
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;                               // 设置时钟分割:TDTS = Tck_tim
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;                           // TIM向上计数模式
    TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure);                                       // 根据指定的参数初始化TIMx的时间基数单位
    TIM_ITConfig(TIM5, TIM_IT_Update, ENABLE);                                            // 使能指定的TIM5中断,允许更新中断
    NVIC_SetPriority(TIM5_IRQn, 7);                                                       // 最低级优先级 中断优先级NVIC设置
    NVIC_EnableIRQ(TIM5_IRQn);                                                            // 使能中断
    TIM_SetCounter(TIM5, 0);                                                              // 设置初始值
    tim5_count = 0x0;                                                                     // 设置初始值
    TIM_Cmd(TIM5, ENABLE);                                                                // 使能TIMx
}

// 开启一个计时器，计时器序号为0 1 2， 要小于 MAX_TIMER_ID
// 5m3x.c       用了 1 2 号定时器
// curtain.c    用了0号定时器
void tim5_start_timer(uint8_t id)
{
    uint64_t tmp;
    do
    {
        tmp = tim5_count | TIM5->CNT;
    } while (tmp != (tim5_count | TIM5->CNT));
    tim5_timer[id] = tmp;
}

// 返回定时器的us数, 计时间隔要小于4294秒
uint32_t tim5_read_started_time_us(uint8_t id)
{
    uint64_t tmp;
    do
    {
        tmp = tim5_count | TIM5->CNT;
    } while (tmp != (tim5_count | TIM5->CNT));

    return (uint32_t)((tmp - tim5_timer[id])) * 100;
}

// 一个等待函数，等待计时器到达
void tim5_wait_timer_reached_us(uint8_t id, uint32_t time_us)
{
    while (tim5_read_started_time_us(id) < time_us)
    {
    }
}